package com.wangxiaonan.wxwork.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.wangxiaonan.wxwork.domain.MessageTemplate;
import com.wangxiaonan.wxwork.domain.ScheduleJob;
import com.wangxiaonan.wxwork.domain.ScheduleJobCriteria;
import com.wangxiaonan.wxwork.exeption.ServiceException;
import com.wangxiaonan.wxwork.repository.ScheduleJobDao;
import com.wangxiaonan.wxwork.service.MessageTemplateService;
import com.wangxiaonan.wxwork.service.ScheduleService;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.Date;
import java.util.List;

@Service
@Transactional
public class ScheduleServiceImpl implements ScheduleService {
    private static final Logger logger = LoggerFactory.getLogger(ScheduleServiceImpl.class);

    @Resource
    private Scheduler scheduler;
    @Resource
    private ScheduleJobDao scheduleJobDao;
    @Resource
    private MessageTemplateService messageTemplateService;

    @Override
    public ScheduleJob getScheduleJobById(Integer id) {
        if (id == null) {
            throw new ServiceException("param_invalid", "参数不能为空");
        }
        return scheduleJobDao.selectByPrimaryKey(id);
    }

    @Override
    public List<ScheduleJob> getScheduleJobs(ScheduleJob scheduleJob) {
        if (scheduleJob == null) {
            throw new ServiceException("param_invalid", "参数不能为空");
        }
        ScheduleJobCriteria sjc = new ScheduleJobCriteria();
        ScheduleJobCriteria.Criteria criteria = sjc.createCriteria();
        if (scheduleJob.getId() != null) {
            criteria.andIdEqualTo(scheduleJob.getId());
        }
        if (StringUtils.isNotBlank(scheduleJob.getName())) {
            criteria.andNameEqualTo(scheduleJob.getName());
        }
        if (StringUtils.isNotBlank(scheduleJob.getGroup())) {
            criteria.andGroupEqualTo(scheduleJob.getGroup());
        }
        if (scheduleJob.getStatus() != null) {
            criteria.andStatusEqualTo(scheduleJob.getStatus());
        }
        if (scheduleJob.getType() != null) {
            criteria.andTypeEqualTo(scheduleJob.getType());
        }
        if (StringUtils.isNotBlank(scheduleJob.getClazz())) {
            criteria.andClazzEqualTo(scheduleJob.getClazz());
        }
        if (scheduleJob.getStartDate() != null) {
            criteria.andStartDateGreaterThanOrEqualTo(scheduleJob.getStartDate());
        }
        if (scheduleJob.getEndDate() != null) {
            criteria.andEndDateLessThanOrEqualTo(scheduleJob.getEndDate());
        }
        sjc.setOrderByClause("f_id asc");
        return scheduleJobDao.selectByCriteria(sjc);
    }

    @Override
    public List<ScheduleJob> getScheduleJobsWithBLOBs(ScheduleJob scheduleJob) {
        if (scheduleJob == null) {
            throw new ServiceException("param_invalid", "参数不能为空");
        }
        ScheduleJobCriteria sjc = new ScheduleJobCriteria();
        ScheduleJobCriteria.Criteria criteria = sjc.createCriteria();
        if (scheduleJob.getId() != null) {
            criteria.andIdEqualTo(scheduleJob.getId());
        }
        if (StringUtils.isNotBlank(scheduleJob.getName())) {
            criteria.andNameEqualTo(scheduleJob.getName());
        }
        if (StringUtils.isNotBlank(scheduleJob.getGroup())) {
            criteria.andGroupEqualTo(scheduleJob.getGroup());
        }
        if (scheduleJob.getStatus() != null) {
            criteria.andStatusEqualTo(scheduleJob.getStatus());
        }
        if (scheduleJob.getType() != null) {
            criteria.andTypeEqualTo(scheduleJob.getType());
        }
        if (StringUtils.isNotBlank(scheduleJob.getClazz())) {
            criteria.andClazzEqualTo(scheduleJob.getClazz());
        }
        if (scheduleJob.getStartDate() != null) {
            criteria.andStartDateGreaterThanOrEqualTo(scheduleJob.getStartDate());
        }
        if (scheduleJob.getEndDate() != null) {
            criteria.andEndDateLessThanOrEqualTo(scheduleJob.getEndDate());
        }
        sjc.setOrderByClause("f_id asc");
        return scheduleJobDao.selectByCriteriaWithBLOBs(sjc);
    }

    @Override
    public ScheduleJob save(ScheduleJob scheduleJob) {
        JSONObject template = JSONObject.parseObject(scheduleJob.getData());
        if (template == null || template.isEmpty()) {
            throw new ServiceException("param_invalid", "参数为空");
        }
        JSONObject schedule = template.getJSONObject("schedule");
        if (schedule == null || schedule.isEmpty()) {
            throw new ServiceException("param_invalid", "参数为空");
        }
        template.remove("schedule");

        // save template
        MessageTemplate messageTemplate = new MessageTemplate();
        messageTemplate.setTemplate(template.toJSONString());
        int tResult = messageTemplateService.save(messageTemplate);
        if (tResult <= 0) {
            throw new ServiceException("insert_fail", "template insert fail");
        }
        JSONObject data = new JSONObject();
        data.put("template_id", messageTemplate.getId());
        data.put("agent_id", scheduleJob.getGroup());
        ScheduleJob job = schedule.toJavaObject(ScheduleJob.class);
        if (StringUtils.isBlank(job.getGroup())) {
            job.setGroup(scheduleJob.getGroup());
        }
        if (job.getStatus() == null) {
            job.setStatus(ScheduleJob.STATUS_VALID);
        }
        job.setData(data.toJSONString());
        if (StringUtils.isBlank(job.getCronExpression()) || StringUtils.isBlank(job.getName())
                || StringUtils.isBlank(job.getClazz())) {
            throw new ServiceException("param_invalid", "关键参数不能为空");
        }
        int sResult = scheduleJobDao.insert(job);
        if (sResult <= 0) {
            throw new ServiceException("insert_fail", "schedule insert fail");
        }
        return job;
    }

    @Override
    public ScheduleJob updateSchedule(ScheduleJob scheduleJob) {
        JSONObject template = JSONObject.parseObject(scheduleJob.getData());
        if (template == null || template.isEmpty()) {
            throw new ServiceException("param_invalid", "参数为空");
        }
        JSONObject schedule = template.getJSONObject("schedule");
        if (schedule == null || schedule.isEmpty()) {
            throw new ServiceException("param_invalid", "参数为空");
        }
        template.remove("schedule");

        ScheduleJob job = schedule.toJavaObject(ScheduleJob.class);
        JSONObject jobData = new JSONObject();

        // 更新template
        Integer templateId = schedule.getInteger("template_id");
        if (templateId == null) {
            throw new ServiceException("param_invalid", "模板编号不能为空");
        }
        MessageTemplate messageTemplate = new MessageTemplate();
        messageTemplate.setTemplate(template.toJSONString());
        messageTemplate.setId(templateId);
        int tResult = messageTemplateService.updateById(messageTemplate);
        if (tResult <= 0) {
            throw new ServiceException("insert_fail", "template insert fail");
        }

        if (StringUtils.isBlank(job.getGroup())) {
            job.setGroup(scheduleJob.getGroup());
        }

        if (job.getStatus() == null) {
            job.setStatus(ScheduleJob.STATUS_VALID);
        }

        scheduleJob = scheduleJobDao.selectByPrimaryKey(job.getId());
        try {
            boolean isExists = scheduler.checkExists(scheduleJob.getJobKey());
            if (isExists) {
                scheduler.unscheduleJob(scheduleJob.getTriggerKey());
            }
        } catch (SchedulerException e) {
            throw new ServiceException("unschedule_fail", "停止任务失败");
        }

        jobData.put("template_id", messageTemplate.getId());
        jobData.put("agent_id", scheduleJob.getGroup());
        job.setData(jobData.toJSONString());
        if (StringUtils.isBlank(job.getCronExpression()) || StringUtils.isBlank(job.getName())
                || StringUtils.isBlank(job.getClazz())) {
            throw new ServiceException("param_invalid", "关键参数不能为空");
        }
        int sResult = scheduleJobDao.updateByPrimaryKey(job);
        if (sResult <= 0) {
            throw new ServiceException("insert_fail", "schedule insert fail");
        }
        return job;
    }

    @Override
    public int update(ScheduleJob scheduleJob) {
        return scheduleJobDao.updateByPrimaryKey(scheduleJob);
    }

    @Override
    public int update(List<ScheduleJob> scheduleJobs) {
        for (ScheduleJob s : scheduleJobs) {
            scheduleJobDao.updateByPrimaryKey(s);
        }
        return 0;
    }

    @Override
    public int deleteById(Integer id) {
        return scheduleJobDao.deleteByPrimaryKey(id);
    }

    @Override
    public int delete(ScheduleJob scheduleJob) {
        return 0;
    }

    @Override
    public int delete(List<ScheduleJob> scheduleJobs) {
        return 0;
    }

    @Override
    public void clearJob() throws ServiceException {
        try {
            scheduler.clear();
        } catch (SchedulerException e) {
            logger.error("[ScheduleServiceImpl] schedule clear fail", e);
            throw new ServiceException("schedule_clear_fail", e.getMessage());
        }
    }

    @Override
    public Date scheduleJob(ScheduleJob job) throws ServiceException {
        if (job == null) {
            throw new ServiceException("param_invalid", "参数不能为空");
        }
        Date date = null;
        if (job.isValid()) {
            try {
                date = scheduler.scheduleJob(job.getJobDetail(), job.getTrigger());
                logger.info("[ScheduleServiceImpl] scheduleJob started >>> id: {}", job.getId());
            } catch (SchedulerException | ClassNotFoundException | ParseException e) {
                logger.error("[ScheduleServiceImpl] scheduleJob fail >>> {}", job.getId(), e);
                throw new ServiceException("schedule_fail", "任务启动失败");
            }
        }
        return date;
    }

    @Override
    public boolean reScheduleJob(ScheduleJob job) throws ServiceException {

        return false;
    }

    @Override
    public boolean unScheduleJob(ScheduleJob job) throws ServiceException {
        if (job == null) {
            throw new ServiceException("param_invalid", "参数不能为空");
        }
        boolean isExists = false;
        try {
            isExists = scheduler.checkExists(job.getJobKey());
        } catch (SchedulerException e) {
            logger.error("[ScheduleServiceImpl] checkExists >>>> fail", e);
        }
        if (isExists) {
            try {
                return scheduler.unscheduleJob(job.getTriggerKey());
            } catch (SchedulerException e) {
                logger.error("[ScheduleServiceImpl] checkExists >>>> fail", e);
            }
        }
        return false;
    }

    @Override
    public boolean unScheduleJobs(List<ScheduleJob> jobs) throws ServiceException {
        return false;
    }

    @Override
    public boolean checkExists(JobKey jobKey) throws ServiceException {
        if (jobKey == null || StringUtils.isBlank(jobKey.toString())) {
            return false;
        }
        try {
            return scheduler.checkExists(jobKey);
        } catch (SchedulerException e) {
            logger.error("[ScheduleServiceImpl] checkExists >>>> fail", e);
            return false;
        }
    }
}
